﻿

#ifndef __CIRCULAR_BUFFER_INCLUDED_H
#define __CIRCULAR_BUFFER_INCLUDED_H
////////////////////////////////////////////////////////////////////////////////
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
#pragma once
#endif
////////////////////////////////////////////////////////////////////////////////
#include <asio++/debug.h>
////////////////////////////////////////////////////////////////////////////////
// 非线程安全类
////////////////////////////////////////////////////////////////////////////////
typedef const char* name_t;
////////////////////////////////////////////////////////////////////////////////
class circular_buffer{
    typedef unsigned char uchar;
public:
    typedef std::shared_ptr<circular_buffer> value_type;
    static value_type create(size_t size = 8192){
        return value_type(new circular_buffer(size));
    }
    virtual ~circular_buffer(){
        delete[] m_data;
    }
    inline size_t peep(void *buffer, size_t bytes){
        return peep(buffer, bytes, 0);
    }
    inline size_t peep(void *buffer, size_t bytes, size_t begin){
        return peep((uchar*)buffer, bytes, begin);
    }
    inline size_t limit(size_t bytes){
        return (m_limit = pow_of_2(bytes));
    }
    inline bool empty() const{
        return (used() == 0);
    }
    inline size_t erase(size_t bytes){
        bytes = std::min<size_t>(used(), bytes);
        m_read += bytes;
        if (m_limit && m_limit < size()){
            if (used() < m_limit){
                resize(m_limit);
            }
        }
        return bytes;
    }
    inline size_t read(void *buffer, size_t bytes){
        return read((uchar*)buffer, bytes);
    }
    inline size_t write(const void *data, size_t bytes){
        size_t need = amount(bytes);
        if (m_limit && need > m_limit){
            return 0;
        }
        if (need > size()){
            if (resize(need) < need){
                return 0;
            }
        }
        return push((uchar*)data, bytes);
    }
    inline void   clear(){erase(used());}
    inline size_t limit() const{return m_limit;}
    inline size_t size()  const{return m_size;}
    inline size_t used()  const{return m_write - m_read;}
    inline size_t freed() const{return m_size - used();}
private:
    inline circular_buffer(size_t size)
        : m_size(pow_of_2(size))
    {
        m_limit = m_size;
        m_read  = m_write = 0;
        m_data  = new uchar[m_size];
    }
    circular_buffer(const circular_buffer&);
    circular_buffer& operator=(const circular_buffer&);
private:
    uchar* m_data;
    size_t m_size, m_limit;
    size_t m_read, m_write;
private:
    static size_t pow_of_2(size_t bytes){
        if ((bytes & (bytes - 1)) == 0){
            return bytes;
        }
        size_t result = 1;
        size_t number = sizeof(size_t) * 8;
        for (size_t i = 0; i < number - 1; i++){
            if ((result <<= 1) >= bytes)
                break;
        }
        return std::min<size_t>(result, ~0);
    }
    size_t resize(size_t bytes){
        uchar *p = new uchar[bytes];
        if (!p){
            return 0;
        }
        m_write = peep(p, used());
        m_read  = 0;
        m_size  = bytes;
        delete[] m_data;
        return (m_data = p), bytes;
    }
    size_t amount(size_t bytes){
        return pow_of_2(used() + bytes);
    }
    size_t read(uchar *buffer, size_t bytes){
        return erase(peep(buffer, bytes, 0));
    }
    size_t peep(uchar *buffer, size_t bytes, size_t begin){
        /* corrected read offset */
        begin = std::min<size_t>(begin, used());
        m_read += begin;

        size_t first, offset;
        size_t maxlen = used();
        bytes = std::min<size_t>(bytes, maxlen);

        /* first get the data from fifo->out until the end of the buffer */
        offset = (m_read & (m_size - 1));
        first = std::min<size_t>(bytes, m_size - offset);
        memcpy(buffer, m_data + offset, first);

        /* then get the rest (if any) from the beginning of the buffer */  
        memcpy(buffer + first, m_data, bytes - first);
        m_read -= begin;
        return bytes;
    }
    size_t push(const uchar *data, size_t bytes){
        size_t first, offset;
        size_t maxlen = freed();
        bytes = std::min<size_t>(bytes, maxlen);

        /* first put the data starting from fifo->in to buffer end */
        offset = (m_write & (m_size - 1));
        first = std::min<size_t>(bytes, m_size - offset);
        memcpy(m_data + offset, data, first);

        /* then put the rest (if any) at the beginning of the buffer */
        memcpy(m_data, data + first, bytes - first);
        return (m_write += bytes), bytes;
    }
};
////////////////////////////////////////////////////////////////////////////////
#endif //__CIRCULAR_BUFFER_INCLUDED_H
